package org.six11.ss.server;

import java.io.PrintWriter;
import java.util.List;
import java.util.Set;

import org.jdom.Element;
import org.six11.ss.server.bean.Game;
import org.six11.ss.server.bean.Person;
import org.six11.ss.server.bean.Room;
import org.six11.ss.server.bean.Round;
import org.six11.ss.server.bean.Score;
import org.six11.ss.shared.Message;
import org.six11.util.adt.MultiState;

/**
 * 
 * 
 * @author Gabe Johnson <johnsogg@cmu.edu>
 */
public class ScoreHandler extends AppletMessageHandler {

  /**
   * @param state
   */
  public ScoreHandler(MultiState state) {
    super(state);
  }

  /**
   * 
   */
  @Override
  public void handle(Message m, String sessionID, PrintWriter out) {
    bug("ScoreHandler does not handle client messages yet.");
  }

  /**
   * Sends the scores to those in the game room.
   * 
   * This includes
   * 
   * @param roomID
   *          The room in question.
   * @param lifetime
   *          If true, include "lifetimeScore" scores for participants.
   * @param game
   *          If true, include "gameScore" scores for participants.
   * @param round
   *          If true, include "roundScore" scores for the most current round.
   */
  public void sendScores(String roomID, boolean lifetime, boolean game, boolean round) {
    // avoid the (unlikely) event where all three booleans are false.
    if (!lifetime && !game && !round)
      return;
    Message scores = new Message("scores");
    try {
      Room room = loadRoom(roomID);
      Set<Person> players = room.getPlayers();
      for (Person p : players) {
        writeScore(scores, p, lifetime, game, round);
      }
      RoomHandler rh = (RoomHandler) getHandler("room");
      rh.sendMessageToAll(scores.copy(), room);
    } catch (Exception ex) {
      log("Unable to send scores to room " + roomID);
      ex.printStackTrace();
    }
  }

  private long convert(Object result) {
    long s = 0L;
    if (result != null) {
      s = (Long) result;
    }
    return s;
  }

  public void awardPoints(String playerID, int numPoints) {
    try {
      Person person = loadPerson(playerID);
      Game game = person.getRoom().getCurrentGame();
      Round round = game.getCurrentRound();
      Score score = new Score();
      score.setPerson(person);
      score.setGame(game);
      score.setRound(round);
      score.setScore(numPoints);
      getSession().save(score);
      Message awardMsg = new Message("pointsAwarded");
      awardMsg.addParam("points", numPoints + "");
      getMessageQueue(person).add(awardMsg);
    } catch (Exception ex) {
      log("Unable to award points to player " + playerID);
    }
  }

  /**
   * Write the specified scores to the given message as a <score> element.
   */
  private void writeScore(Message msg, Person p, boolean lifetime, boolean game, boolean round) {
    try {
      Element score = new Element("score");
      score.setAttribute("playerNick", p.getNick());

      Room room = p.getRoom();

      if (lifetime) {
        long s = convert(getSession().createQuery("select sum(score) from Score where personID=?")
            .setInteger(0, p.getId()).uniqueResult());
        score.setAttribute("lifetimeScore", "" + s);
      }
      if (game) {
        long s = convert(getSession().createQuery(
            "select sum(score) from Score where personID=? and gameID=?").setInteger(0, p.getId())
            .setInteger(1, room.getCurrentGame().getId()).uniqueResult());
        score.setAttribute("gameScore", "" + s);
      }
      if (round) {
        long s = convert(getSession().createQuery(
            "select sum(score) from Score where personID=? and roundID=?").setInteger(0, p.getId())
            .setInteger(1, room.getCurrentGame().getCurrentRound().getId()).uniqueResult());
        score.setAttribute("roundScore", "" + s);
      }
      msg.addElement(score);
    } catch (Exception ex) {
      // this is not an error if the person left (or was booted from) a game.
    }
  }
}
